package scuba.DiveBuddy.data;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.google.android.gms.maps.model.LatLng;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import scuba.DiveBuddy.Class.AirMix;
import scuba.DiveBuddy.Class.DiverProfile;
import scuba.DiveBuddy.Class.LogEntry;
import scuba.DiveBuddy.Enums.*;

import java.util.ArrayList;
import java.util.Date;

/**
 * Created by Alexander Anderson on 11/02/14.
 */
public class LogEntrySource {
    private static String TABLE_NAME = "LogEntries";

    private static String COLUMN_ID = "DiveID";
    private static String COLUMN_DIVER = "DiverID";
    private static String COLUMN_DIVENUM = "DiveNumber";
    private static String COLUMN_DIVEDATE = "DiveDate";
    private static String COLUMN_TIMEIN = "TimeIn";
    private static String COLUMN_TIMEOUT = "TimeOut";
    private static String COLUMN_MAXDEPTH = "MaxDepth";
    private static String COLUMN_DEPTHUNITS = "DepthUnits";
    private static String COLUMN_DIVETYPE = "DiveType";
    private static String COLUMN_OBSERVATIONNOTES = "Observations";
    private static String COLUMN_LOCATIONLAT = "LocationLat";
    private static String COLUMN_LOCATIONLONG = "LocationLong";
    private static String COLUMN_STARTAIR = "StartAir";
    private static String COLUMN_ENDAIR = "EndAir";
    private static String COLUMN_AIRUNITS = "AirUnits";
    private static String COLUMN_ALTITUDE = "Altitude";
    private static String COLUMN_ALTUNITS = "AltitudeUnits";
    private static String COLUMN_WATERTYPE = "WaterType";
    private static String COLUMN_AIRMIX = "AirMix";
    private static String COLUMN_EXPOSURE = "Exposure";
    private static String COLUMN_THICKNESS = "ExposureThickness";
    private static String COLUMN_TEMPSURFACE = "SurfaceTemp";
    private static String COLUMN_TEMPDEPTH = "DepthTemp";
    private static String COLUMN_TEMPUNITS = "TempUnits";
    private static String COLUMN_WEIGHT = "Weight";
    private static String COLUMN_WEIGHTUNITS = "WeightUnits";
    private static String COLUMN_VISIBILITY = "Visibility";
    private static String COLUMN_VISUNITS = "VisUnits";

    //TABLE MOD [#STATICS]
    public static void CreateTable(SQLiteDatabase db) {
        String create = "create table " + TABLE_NAME  +" (" +
                COLUMN_ID + " integer primary key autoincrement," +
                COLUMN_DIVER + " integer not null," +
                COLUMN_DIVENUM + " integer," +
                COLUMN_DIVEDATE + " integer not null," +
                COLUMN_TIMEIN + " integer not null," +
                COLUMN_TIMEOUT + " integer not null," +
                COLUMN_MAXDEPTH + " real not null," +
                COLUMN_DEPTHUNITS + " integer not null," +
                COLUMN_DIVETYPE + " integer not null," +
                COLUMN_OBSERVATIONNOTES + " varchar(256) not null," +
                COLUMN_LOCATIONLAT + " real," +
                COLUMN_LOCATIONLONG + " real," +
                COLUMN_STARTAIR + " integer," +
                COLUMN_ENDAIR + " integer," +
                COLUMN_AIRUNITS + " integer," +
                COLUMN_ALTITUDE + " integer," +
                COLUMN_ALTUNITS + " integer," +
                COLUMN_WATERTYPE + " integer not null," +
                COLUMN_AIRMIX + " integer not null," +
                COLUMN_EXPOSURE + " integer," +
                COLUMN_THICKNESS + " real," +
                COLUMN_TEMPSURFACE + " real," +
                COLUMN_TEMPDEPTH + " real," +
                COLUMN_TEMPUNITS + " integer," +
                COLUMN_WEIGHT + " real," +
                COLUMN_WEIGHTUNITS + " integer," +
                COLUMN_VISIBILITY + " real," +
                COLUMN_VISUNITS + " integer);";

        Log.w("DATABASE", "Creating table " + TABLE_NAME + " with STATEMENT = '" + create + "'");

        try {
            Log.w("DATABASE", "Created table " + TABLE_NAME);
            db.execSQL(create);
        }
        catch(SQLException sql) {
            Log.e("DATABASE", "Create Failed on " + TABLE_NAME + " with error = '" + sql + "'");
        }
    }
    public static void DropTable(SQLiteDatabase db) {
        String drop = "drop table if exists " + TABLE_NAME;

        Log.w("DATABASE",
                "Dropping table " + TABLE_NAME + " with STATEMENT = '" + drop + "'");

        try {
            Log.w("DATABASE", "Table " + TABLE_NAME + " Dropped");
            db.execSQL(drop);
        }
        catch(SQLException sql) {
            Log.e("DATABASE", "Failed to drop table " + TABLE_NAME + " with error = '" + sql + "'");
        }
    }
    public static void UpgradeTable(SQLiteDatabase db) {
        DropTable(db);
        CreateTable(db);
    }

    public static void Cleanse() {
        UpgradeTable(Database.getInstance().getDatabase("LogEntrySource::Cleanse()"));
    }

    //Methods
    private static ContentValues getContentValues(LogEntry entry) {
        ContentValues values = new ContentValues();
        values.put(COLUMN_DIVEDATE,entry.getDiveDate().toDateTimeAtStartOfDay().getMillis());
        values.put(COLUMN_DIVER, DiverProfile.getActiveProfile().getID());
        values.put(COLUMN_DIVENUM, entry.getDiveNumber());
        values.put(COLUMN_TIMEIN, entry.getTimeIn().toDateTimeToday().getMillis());
        values.put(COLUMN_TIMEOUT, entry.getTimeOut().toDateTimeToday().getMillis());
        values.put(COLUMN_MAXDEPTH, entry.getMaxDepth());
        values.put(COLUMN_DEPTHUNITS, entry.getDepthUnits().Value);
        values.put(COLUMN_DIVETYPE, entry.getDiveType().Value);
        values.put(COLUMN_OBSERVATIONNOTES, entry.getObservations());
        values.put(COLUMN_WATERTYPE, entry.getWaterType().Value);
        values.put(COLUMN_AIRMIX, entry.getAirMix().getID());
        values.put(COLUMN_DIVENUM, entry.getDiveNumber());

        LatLng l = entry.getLocationData();
        values.put(COLUMN_LOCATIONLAT, l == null ? null : l.latitude);
        values.put(COLUMN_LOCATIONLONG, l == null ? null : l.longitude);
        values.put(COLUMN_STARTAIR, entry.getStartAir());
        values.put(COLUMN_ENDAIR, entry.getEndAir());
        values.put(COLUMN_AIRUNITS, entry.getAirUnits().Value);
        values.put(COLUMN_ALTITUDE, entry.getAltitude());
        values.put(COLUMN_ALTUNITS, entry.getAltitudeUnits().Value);

        values.put(COLUMN_EXPOSURE, entry.getExposureSuit().Value);
        values.put(COLUMN_THICKNESS, entry.getExposureProtectionMM());
        values.put(COLUMN_TEMPSURFACE, entry.getSurfaceTemperature());
        values.put(COLUMN_TEMPDEPTH, entry.getDepthTemperature());
        values.put(COLUMN_TEMPUNITS, entry.getTemperatureUnits().Value);
        values.put(COLUMN_WEIGHT, entry.getWeight());
        values.put(COLUMN_WEIGHTUNITS, entry.getWeightUnits().Value);
        values.put(COLUMN_VISIBILITY, entry.getVisibility());
        values.put(COLUMN_VISUNITS, entry.getVisibilityUnits().Value);

        return values;
    }

    public static int CreateLogEntry(LogEntry entry) {
        SQLiteDatabase db = Database.getInstance().getDatabase("LogEntrySource::CreateLogEntry()");

        ContentValues values = getContentValues(entry);
        long id = db.insert(TABLE_NAME, null, values);
        return (int)id;
    }
    public static boolean UpdateLogEntry(LogEntry entry) {

        Log.v("DATABASE", "Call to LogEntrySource::UpdateLogEntry() --> method not implemented");

        ContentValues values = getContentValues(entry);

        SQLiteDatabase db = Database.getInstance().getDatabase("LogEntrysource:UpdateLogEntry()");

        int rows = db.update(TABLE_NAME, values, COLUMN_ID + "=" + entry.getID(), null);

        if(rows == 0) {
            Log.e("DATABASE", "UpdateLogEntry() Update affected nothing");
            return false;
        }
        else if(rows == 1)
            return true;
        else {
            Log.e("DATABASE", "UpdateLogEntry() Update affected more then one row");
            return false;
        }


    }

    public static ArrayList<LogEntry> GetEntries(int diverID) {

        SQLiteDatabase db = Database.getInstance().getDatabase("LogEntrySource::GetEntries()");
        String query = "SELECT * FROM " + TABLE_NAME + " WHERE " + COLUMN_DIVER + "=" + diverID +" ORDER BY " + COLUMN_DIVEDATE;
        ArrayList<LogEntry> entries = new ArrayList<LogEntry>();

        Cursor c = db.rawQuery(query, null);
        if(c.getCount() == 0) {
            c.close();
            Log.w("DATABASE", "Query: '" + query + "' returned null");
            return entries; //nothing
        }
        c.moveToFirst();

        for(int i =0 ; i < c.getCount(); i++, c.moveToNext()) {

            Integer lat = c.getInt(c.getColumnIndex(COLUMN_LOCATIONLAT));
            Integer lng = c.getInt(c.getColumnIndex(COLUMN_LOCATIONLONG));

            LatLng location = null;
            if(lat.equals(null) && lng.equals(null))
                location = null;
            else
                location = new LatLng(lat, lng);

            LogEntry e = new LogEntry(
                    c.getInt(c.getColumnIndex(COLUMN_ID)),
                    c.getInt(c.getColumnIndex(COLUMN_DIVENUM)),
                    new LocalDate(c.getLong(c.getColumnIndex(COLUMN_DIVEDATE))),
                    new LocalTime(c.getLong(c.getColumnIndex(COLUMN_TIMEIN))),
                    new LocalTime(c.getLong(c.getColumnIndex(COLUMN_TIMEOUT))),
                    c.getFloat(c.getColumnIndex(COLUMN_MAXDEPTH)),
                    DistanceEnum.values()[c.getInt(c.getColumnIndex(COLUMN_DEPTHUNITS)) - 1],
                    DiveTypeEnum.values()[c.getInt(c.getColumnIndex(COLUMN_DIVETYPE)) - 1],
                    c.getString(c.getColumnIndex(COLUMN_OBSERVATIONNOTES)),
                    location,
                    c.getFloat(c.getColumnIndex(COLUMN_STARTAIR)),
                    c.getFloat(c.getColumnIndex(COLUMN_ENDAIR)),
                    PressureUnitsEnum.values()[c.getInt(c.getColumnIndex(COLUMN_AIRUNITS)) - 1],
                    c.getFloat(c.getColumnIndex(COLUMN_ALTITUDE)),
                    DistanceEnum.values()[c.getInt(c.getColumnIndex(COLUMN_ALTUNITS)) - 1],
                    WaterTypeEnum.values()[c.getInt(c.getColumnIndex(COLUMN_WATERTYPE)) - 1],
                    AirMix.GetByID(c.getInt(c.getColumnIndex(COLUMN_AIRMIX))),
                    ExposureTypeEnum.values()[c.getInt(c.getColumnIndex(COLUMN_EXPOSURE)) - 1],
                    c.getFloat(c.getColumnIndex(COLUMN_THICKNESS)),
                    c.getFloat(c.getColumnIndex(COLUMN_TEMPSURFACE)),
                    c.getFloat(c.getColumnIndex(COLUMN_TEMPDEPTH)),
                    TemperatureUnitsEnum.values()[c.getInt(c.getColumnIndex(COLUMN_TEMPUNITS)) - 1],
                    c.getFloat(c.getColumnIndex(COLUMN_WEIGHT)),
                    WeightUnitsEnum.values()[c.getInt(c.getColumnIndex(COLUMN_WEIGHTUNITS)) - 1],
                    c.getFloat(c.getColumnIndex(COLUMN_VISIBILITY)),
                    DistanceEnum.values()[c.getInt(c.getColumnIndex(COLUMN_VISUNITS)) - 1]);

            entries.add(e);
        }

        c.close();
        return entries;
    }

    //GraphViews
}
